package com.qf.smsplatform.interfaces.mq;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qf.smsplatform.common.constants.CacheConstants;
import com.qf.smsplatform.common.constants.RabbitMQConstants;
import com.qf.smsplatform.common.model.StandardReport;
import com.qf.smsplatform.interfaces.config.DelayedConfig;
import com.qf.smsplatform.interfaces.service.api.CacheService;
import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.util.Map;

@Component
@Slf4j
public class PushSmsReportListener {

    @Autowired
    private CacheService cacheService;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    private Integer[] sendTTL = {0,10000,30000,60000,300000};


    // 第一次推送状态报告
    @RabbitListener(queues = RabbitMQConstants.TOPIC_PUSH_SMS_REPORT)
    public void consume(StandardReport report, Channel channel, Message message) throws IOException {
        //1. 获取当前客户的id
        long clientID = report.getClientID();
        //2. 去缓存模块查询当前客户的信息
        Map map = cacheService.hMGet(CacheConstants.CACHE_PREFIX_CLIENT + clientID);
        //3. 判断当前客户的isreturnstatus是否为1
        Integer isReturnStatus = Integer.parseInt((String) map.get("isreturnstatus"));
        // 如果为1，状态报告的推送
        if(isReturnStatus != null && isReturnStatus == 1) {
            //3.1 查询当前客户的接收状态报告的http路径,并封装数据
            String receiveStatusUrl = (String) map.get("receivestatusurl");
            report.setReceiveStatusUrl(receiveStatusUrl);
            report.setSendCount(1);   // 第一次推送
            String result = null;
            result = sendReport(report, result);   // 发送请求的同时,判断是否出现了异常
            if(result == null){
                channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
                return;
            }
            //3.4 如果客户接收到请求后，响应得数据为SUCCESS，确定客户已经接收到状态报告
            isSuccess(report, result);            // 发送请求后,如果没有出现异常,判断是不是SUCCESS
        }else {
            log.info("【接口模块】推送状态报告给用户 -- 当前用户未开启推送状态报告。。。 clientID = {}", clientID);
        }
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }

    // 第N次推送状态报告(除了第一次)
    @RabbitListener(queues = DelayedConfig.DELAYED_QUEUE)
    public void delayedConsume(StandardReport report, Channel channel, Message message) throws IOException {
        //1. 封装report对象
        report.setSendCount(report.getSendCount() + 1);
        //2. 封装请求头和请求参数,发送请求
        String result = null;
        result = sendReport(report, result);
        if(result == null){
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
            return;
        }
        //4. 如果返回的不是SUCCESS,再次发送消息到延迟队列,记录日志,发送失败
        isSuccess(report, result);
        //6. ack
        channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
    }

    private String sendReport(StandardReport report, String result) {
        try {
            HttpHeaders headers = new HttpHeaders();  // 封装请求头
            headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
            HttpEntity httpEntity = new HttpEntity(objectMapper.writeValueAsString(report),headers); // 封装请求数据
            result = restTemplate.postForObject(report.getReceiveStatusUrl(), httpEntity, String.class);  // 发送请求
        } catch (JsonProcessingException | RestClientException e) {
            //3. 如果出现异常,再次发送消息到延迟队列,记录日志,发送失败
            sendDelayedMsg(report);
            return null;
        }
        return result;
    }

    private void sendDelayedMsg(StandardReport report) {
        log.info("【接口模块】推送状态报告给用户 -- 第{}次发送，客户没有接收到状态报告。。。", report.getSendCount());
        if (report.getSendCount() != 4) { // 如果已经发送到第4次了，发送延迟消息了。
            // 发送消息到延迟交换机中,并设置消息的生存时间.
            rabbitTemplate.convertAndSend(DelayedConfig.DELAYED_EXCHANGE, "routingKey", report, new MessagePostProcessor() {
                @Override
                public Message postProcessMessage(Message message) throws AmqpException {
                    message.getMessageProperties().setDelay(sendTTL[report.getSendCount()]);
                    return message;
                }
            });
        }
    }

    private void isSuccess(StandardReport report, String result) {
        if (!"SUCCESS".equals(result)) {
            sendDelayedMsg(report);
        } else {
            //5. 如果返回的是SUCCESS,状态报告推送成功,记录日志
            log.info("【接口模块】推送状态报告给用户 -- 客户已经接收到状态报告！！！");
        }
    }


}
